Los controladores son una parte esencial del framework Laravel, con un controlador podemos agregarle dinamismo a nuestra aplicación ya que nos permite interactuar con modelos y otras clases de nuestra aplicación. En este artículo vamos a resaltar 10 características que no deberíamos olvidar.
1. Controlador de Recurso (Resource Controller)
Con Laravel crear un controlador que tenga todos los métodos necesarios para un CRUD es muy simple, gracias a la consola interactiva se puede crear con este simple comando:
php artisan make:controller UserController --resource
Además de crear un controlador para un CRUD, se puede asociar el controlador a un modelo añadiendo la opción model
al comando anterior de esta forma:
php artisan make:controller UserController --resource --model=User
Para enlazar a estos controladores con todos sus métodos podemos hacerlo de forma simple en nuestras rutas sin tener que definir cada una, para hacerlo debemos usar el método resource
:
Route::resource('users', 'UserController');
En el caso de no utilizar algún método en específico, se puede desactivar utilizando el método except
y en el caso de que solo queramos utilizar los que especifiquemos, se puede hacer con el método only
como se muestra a continuación:
Route::resource('users', 'UserController')->only([ 'index', 'show', 'destroy' ]); Route::resource('Users', 'UserController')->except([ 'create', 'store' ]);
Si estas construyendo una API y deseas generar rápidamente un controlador de recursos que no incluya los métodos de create
y edit
, utiliza la opción --api
del comando make:controller
:
php artisan make:controller Api/UserController --api
Para hacer referencia a este controlador desde las rutas puedes llamar al método apiResource
, este método cumple la misma función que el método resource
que vimos anteriormente pero excluye los métodos create
y edit
.
Route::apiResource('users', 'UserController');
Si tienes otros controladores para recursos tipo API puedes utilizar el mismo método para añadir varios pasando un arreglo como argumento de esta forma:
Route::apiResources([ 'users' => 'UserController', 'posts' => 'PostController' ])
2. Ubicación de los controladores
Si estamos trabajando en un proyecto algo grande puede ser una buena idea separar los controladores en distintas carpetas según la lógica de negocio. Por ejemplo, si tenemos una plataforma de ventas con un panel administrativo y de clientes sería una buena idea colocar los controladores de administración en una carpeta admin
y los relacionados con los clientes en una carpeta clients
.
No olvides modificar los nombres de espacio necesarios para que Composer pueda auto-cargar todos los controladores desde sus nuevas ubicaciones.
Adicionalmente, debes especificar el espacio de nombre (namespace) del controlador en las rutas de la siguiente manera:
Route::get('index', 'Admin\ProductController@index');
Esto es porque Laravel -por defecto- asume que los controladores tienen el espacio de nombre App\Http\Controllers
por tanto, debes añadir lo faltante como en el código anterior.
Puedes aprender a configurar y agrupar las rutas de tu aplicación usando el RouteServiceProvider de Laravel.
3. Controladores de un solo método
Si tienes tiempo desarrollando con Laravel te has encontrado con controladores que cumplen una función muy específica, tanto que solo disponen de un método. Para este tipo de ocasiones, Laravel nos permite utilizar el método mágico __invoke
de esta forma:
<?php namespace App\Http\Controllers; use App\Ticket; use App\Http\Controllers\Controller; class ShowTicket extends Controller { public function __invoke(Ticket $ticket) { return view('tickets.show', compact('ticket')); } }
Después de ver esto quizás te preguntes cómo podemos especificar el llamado de este método desde nuestras rutas. Pues, el método __invoke
será lanzado al intentar llamar a la clase de un controlador sin especificar la acción:
Route::get('ticket/{ticket}', 'ShowTicket');
Aprende con nuestro Curso de Programación Orientada a Objetos con PHP sobre el Uso de los métodos mágicos __toString y __invoke en PHP.
4. Métodos para el retorno de redirecciones
Existen algunos helpers muy útiles que pueden ayudarnos con las respuestas, en el caso de las redirecciones tenemos el helper back()
el cual retorna una redirección hacia la ruta anterior y lo podemos usar de esta forma tan simple:
public function store(Request $request) { User::create($request->all()); return back(); }
The @laravelphp controllers are so complicated sometimes :) pic.twitter.com/NMfS8wbCWZ
— Duilio Palacios (@Sileence) April 16, 2016
Si quieres hacer una simple redirección hacia una dirección específica solo basta con utilizar el helper redirect()
:
public function store(Request $request) { User::create($request->all()); return redirect('/home'); }
Aunque si no te convence especificar rutas estáticas puedes concatenar el método route()
y especificar el nombre de una ruta:
public function store(Request $request) { User::create($request->all()); return redirect()->route('users.index'); }
Podemos redireccionar hacia un dominio externo con el método away()
de la siguiente forma:
public function foo() { return redirect()->away('https://www.styde.net'); }
5. Redirecciones con mensajes de sesión
Los mensajes en la gran mayoría de los casos son muy importantes ya que le indicamos al usuario que está sucediendo; en Laravel podemos redirigir con algún tipo de mensaje desde el método de un controlador y es tan simple como esto:
public function destroy(User $user) { $user->delete(); return back()->with('success', 'Usuario eliminado con éxito.'); }
Con el método with
podemos crear un mensaje de sesión temporal o «flash» si indicamos su nombre y su valor, además podemos mostrarlo en la vista de la siguiente forma:
@if (session('success')) // Comprobamos que exista {{ session('success') }} // Imprimir el contenido indicando el nombre. @endif
Si especificar el nombre y el valor del mensaje de sesión te parece mucho, existe una forma aun más simple siguiendo esta convención withSuccess
el texto remarcado es el nombre del mensaje y como parámetro le pasaríamos el valor, como se puede ver en el siguiente ejemplo:
return back()->withSuccess('Valor del success'); {{ session('success') }} // Valor del success return back()->withStyde('Styde.net'); {{ session('styde') }} // Styde.net
6. Respuestas hacia otros métodos de los controladores
Cuando aprendía Laravel me encontré con algunas dudas y errores que cometía por desconocer la posibilidad de responder hacia otro método. Un ejemplo más claro de lo que intento explicarte puede ser éste:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { public function store(Request $request) { $user = User::create($request->all()); return view('users.show', compact('user')); } public function show(User $user) { return view('users.show', compact('user')); } }
Seguramente ya lo has notado, en el método store
luego de guardar el nuevo usuario se repite lo que hace el método show
y aunque pueda parecer muy obvio, este caso se puede encontrar muy seguido y no es recomendable. Debido a que si en un futuro necesitas agregar algo de lógica a la vista tendrás que modificar dos métodos, además podrás tener problemas por envío duplicado de datos. La solución para evitar tener que reescribir código es redirigir hacía el método del controlador utilizando el método redirectToAction
después del helper response
de esta forma:
public function store(Request $request) { $user = User::create($request->all()); return response()->redirectToAction('UserController@show', $user); }
El método acepta 4 argumentos, donde obligatoriamente debemos especificarle el controlador y la acción, de forma opcional podemos indicar los parámetros del método que estamos llamando, status y header.
7. Otros tipos de respuestas
Anteriormente ya hemos observado como podemos responder redirecciones y quizás ya sabes cómo podemos responder una vista, pero si aun no lo sabes lo podemos hacer usando el helper view
de esta forma:
public function index() { $variable = 'valor'; return view('users.index', compact('variable')); }
El helper view
recibe el nombre de la vista, en caso de estar dentro de carpetas debemos especificarlas y usar los puntos, cabe resaltar que no hace falta especificar la extensión de la vista ya que Laravel se encarga de esto. Como segundo argumento recibe un arreglo asociativo donde las llaves serán los nombres de las variables en la vista y los valores serán el contenido de la variable.
La función compact
de PHP recibe los nombres de las variables a transformar en un arreglo asociativo, para que quede más claro podemos observar este código:
$variable = 'valor'; $temp = compact('variable'); // El contenido de temp es: [ 'variable' => 'valor' ]
Si estás trabajando sobre un controlador específico para un API puedes tener respuestas de tipo JSON de esta forma:
return response()->json([ 'name' => 'Foo Bar', 'website' => 'styde.net' ]);
Se puede resaltar que, por defecto, el método json
configurará automáticamente el encabezado Content-Type
a application/json
.
Podemos responder descargas directas de archivos con el método download
y es muy sencillo:
// Especificamos el path del archivo, el primer argumento es obligatorio, el resto es opcional. return response()->download($direccionDelArchivo, $nombre, $headers); // Podemos llamar el método deleteFileAfterSend // si queremos que sea eliminado el archivo luego de responder. return response()->download($direccionDelArchivo)->deleteFileAfterSend(true);
Con los métodos anteriores estamos retornando una descarga, pero si quieres una visualización de un archivo como puede ser un PDF o un archivo de texto en el navegador podemos hacerlo con el método file
como se muestra a continuación:
// El primer parámetro es obligatorio y el segundo es opcional. return response()->file($direccionDelArchivo, $headers);
8. Métodos authorize para los permisos
Con los controladores podemos comprobar los permisos que tenemos sobre algún recurso, para esto tenemos algunos métodos disponibles:
public function update(Request $request, Post $post) { // Con este método especificamos la acción y el recurso. $this->authorize('update', $post); // Podemos especificar un usuario con este método $this->authorizeForUser($user, 'update', $post); }
Laravel tomará el nombre de la acción y la asociará al recurso que hemos especificado, por ejemplo si definimos un método habitual como update
en la clase de nuestro controlador estaremos comprobando que el usuario autentificado pueda hacer update
sobre el modelo Post
.
Aprende más sobre reglas y permisos con nuestro Curso de Técnicas de autorización con Laravel.
9. Validaciones
Desde los controladores tenemos la posibilidad de validar que estamos recibiendo lo que esperamos, existen algunas formas de cómo podemos hacerlo y vamos a comenzar observando la primera:
// Método store de un controlador public function store(Request $request) { $this->validate($request, [ 'name' => 'string|min:30|max:60', 'email' => 'unique:users,email|required' ], [ 'name.*' => 'Nombre invalido', 'email.required' => 'El correo electronico es un campo obligatorio' ]); }
El método validate
recibe 3 argumentos: el objeto de una instancia Request
, las reglas de validación y los mensajes si queremos personalizarlos, en el ejemplo se muestra cómo se puede personalizar el mensaje completo de un campo o específicamente sobre una regla.
Tenemos otra forma de hacerlo que puede ser más simple, ya que podemos llamar al método validate
desde el objeto Request
de la siguiente forma:
// Método store de un controlador public function store(Request $request) { $request->validate([ 'name' => 'string|min:30|max:60', 'email' => 'unique:users,email|required' ], [ 'name' => 'Nombre invalido', 'email.required' => 'El correo electronico es un campo obligatorio' ]); }
Este método solo recibe dos argumentos: las reglas de validación y como argumento opcional los mensajes personalizados.
Una alternativa a validar en el controlador sobretodo si tienes muchas reglas de validación puede ser el uso de Form Requests: Cómo trabajar con Form Requests en Laravel
10. Inyección de dependencias con el constructor
Uno de los puntos fuertes de Laravel es su Contenedor de inyección de dependencias ya que en el método mágico __construct
todas las dependencias declaradas se resolverán automáticamente y se inyectarán en la instancia del controlador.
Como puedes ver de manera más clara en este ejemplo:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Services\SlackClient; class UserController extends Controller { protected $slack; public function __construct(SlackClient $slack) { $this->slack = $slack; } public function sendMessage(Request $request) { $this->slack->send($request->get('message')); return back(); } }
Este controlador tiene una demostración de un servicio llamado SlackCliente
el cual estará disponible cuando llamemos al método sendMessage
o algún otro dentro del controlador, estoy seguro que has notado la ventaja: ya no necesitamos instanciar la clase en todos los métodos.
Si deseas conocer más de este tema puedes mirar esta lección sobre Inyección de dependencias del curso Crea componentes para PHP y Laravel.
¡Listo por ahora! Si has llegado hasta acá tienes el derecho de presumir con tus colegas tus nuevas habilidades sobre el manejo de controladores en Laravel, además también puedes comentar las dudas que tengas o comentarnos cuál ha sido tu experiencia o dudas con los controladores en Laravel.
Material Relacionado
- Uso de controladores de una sola acción en Laravel 5.4
- Generar controladores asociados a un modelo en Laravel 5.4
- Creación y uso de controladores en Laravel 5.*
Espero que te haya gustado este material. No olvides seguirnos en Twitter y suscribirte a nuestro boletín:
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.