Massassignmentexception In Model.Php Laravel 5 Book

Realizaremos una práctica de acceso a base de datos en Laravel, con varias operaciones a partir de modelos de Eloquent en Laravel 5.

Vamos a hacer una pausa para la práctica en la sección de bases de datos del Manual de Laravel 5. Hemos visto de manera detallada la creación y modificación de tablas mediante las migraciones y además hemos conseguido insertar datos de prueba en las tablas gracias a los seeders, así que nos resta jugar un poco con todo ello.

Nuestro ejercicio nos permitirá poner en práctica los conocimientos que ya poseemos hasta el momento y explorar algún área nueva, sobre todo en lo que respecta a los modelos. El objetivo es realizar un sencillo sistema para listar datos que tenemos en una tabla y para insertar datos nuevos en dicha tabla. Resultará bastante sencillo de entender si digo que nos quedaremos a la mitad del camino de lo que se conoce como CRUD. Osea, veremos solamente el "CR" Create y Read, dejando para más adelante el "UD" Update y Delete.

Nota: Todo lo que vamos a conocer de nuevo en este artículo son cosas que nos ofrece el ORM de Laravel, Eloquent. No es nuestra intención entrar en detalle con este asunto, porque es algo que veremos dentro de poco y para lo que necesitaremos varios artículos. La idea es comenzar a hacer algunos ejemplos en los que podamos ver la sencillez del acceso a datos de Laravel y podamos empezar a generar páginas que nos respondan entregando información que hemos guardado en nuestras tablas.

Aprovecharemos que en los artículos anteriores sobre los seeders poblamos la tabla de libros para usarla en esta práctica. Partimos pues sobre una tabla, ya rellena con información de prueba, llamada "books". Si no la tienes, por favor, sigue los pasos el artículo sobre los Seeders.

Rutas

Comenzaremos observando las rutas nuevas que hemos creado para este ejemplo.

Por orden de aparición, las rutas serán usadas para las siguientes páginas:

  • libros: para ver un listado de todos los libros
  • libros/{id}: para ver un detalle de un libro en particular
  • libros/crear (GET): para mostrar el formulario con el que crearemos libros
  • libros/crear (POST): para recibir el formulario con los datos de un nuevo libro y si valida correctamente, insertarlo

Con la lectura del código de las rutas debería quedar claro que el controlador encargado de ejecutar todas las solicitudes se llama BookController. Los métodos que tendremos que definir, con el código de cada operación, se llaman index(), show(), create(), store().

Nota: Recuerda que tienes más información sobre las rutas en capítulos anteriores. Puedes ver el artículo Parámetros en las rutas, así como Verbos en las rutas.

Controlador BookController

Vamos a contar con un único controlador que realizará todas las acciones que serán necesarias para resolver nuestros objetivos.

El controlador, como sabes, se puede generar con un comando de artisan: “make:controller”. Es parte te la dejamos para ti, porque ya lo vimos en el capítulo de introducción a los controladores, pero sin embargo quiero que prestes atención a los nombres de las acciones en el controlador por defecto que se ha creado. Son los mismos que hemos proyectado en las rutas anteriores, así que ya tenemos mucho del trabajo adelantado.

Nuestro código para gestionar esas acciones se puede ver a continuación:

El listado de todos los libros:
La primera acción debe mostrar todos los libros de la tabla books.

Hacemos una búsqueda de los libros a través del modelo Book. Luego llamamos a una vista que se encargará de mostrar el listado de todos los libros.

Nota: El modelo Book lo debes haber creado al poner en práctica artículos anteriores, puesto que ya lo usamos para crear el seeder de la tabla de libros (books). De todos modos, de momento es un modelo vacío de contenido, por lo que si no lo tienes lo generas directamente con el comando “make:model” del asistente artisan.

Cuando solicitamos información a un modelo como en este caso, Book::all(), lo que nos devuelve el método all() es un objeto colección “collection". No hemos llegado a explicar qué hay de útil detrás de las colecciones y por ahora vamos a dejarlo aparte, pero comenzaremos a usarlas. De momento lo único que hacemos con la colección es invocar el método toArray(), que nos devuelve los datos que contiene, pero en formato de array.

Ese array generado a partir de la colección se lo pasamos a la vista para que sea capaz de pintar los libros que se han encontrado en la consulta a la tabla.

Por cierto, en el controlador no se te debe olvidar hacer el “use” de la clase donde está el modelo Book.

use App\Book;

El detalle de un libro:
La segunda acción que vamos a observar es la que se invoca cuando se solicita el detalle de un libro, método show().

Este método recibe como parámetro el id del libro que se desea visualizar. Ese id se lo pasamos a la ruta y gracias al where() del código de la ruta ya está comprobado que sea un número.

Nota: Recuerda el código de la ruta:



Tal como está construida, solo se activará cuando el parámetro id sea un número.

En esta acción del controlador solicitamos información al modelo de los libros (Book) mediante el método find(), que sirve para buscar un elemento a partir de su clave primaria. Si encontró alguna cosa me devolverá la colección con aquello que se haya encontrado. Si no encuentra nada me devolverá null. En función del valor de retorno, se realizan cosas distintas.

  • Devuelvo una vista para mostrar el libro, en caso que no sea nulo, enviándole a la vista los datos del libro en un array
  • O bien, si no se encontró nada, devuelvo un objeto response con un error 404 de página no encontrada y un mensaje

Formulario de creación de un libro:
Ahora veamos la acción que comienza el proceso de creación de un libro, que se encarga de mostrar el formulario para introducir los datos de un libro.

Este es el más sencillo de todos los métodos del controller, porque solo tiene la llamada a una vista, que tendrá el HTML del formulario de alta de un libro.

Creación del libro, a partir de los datos del formulario:
Para acabar el controlador nos queda ver el método store, que es el que realmente se encarga de crear el nuevo libro.

El método store() recibe la Request, dependencia que se inyecta en la llamada al método de la acción, necesario porque vamos a tener que recuperar los datos de la solicitud POST (los datos enviados en el formulario).

Dentro del método realizamos una validación de los datos recibidos por formulario y si todo ha ido bien, es cuando creamos el recurso, gracias al método create() del modelo Book, enviándole los datos de la solicitud, todos convertidos a array mediante el método all().

Una vez creado el libro en la tabla, se redirige a la página “home” de libros, que se encarga de mostrar el listado de los libros que hay en el sistema.

Esta es la parte más compleja de la práctica, porque entran en juego las validaciones, sin embargo esperamos que puedas recordar los mecanismos que ya fueron relatados en el artículo de validaciones en Laravel.

Modificación en el modelo Book

Tal como está nuestro código y el uso que hacemos del modelo con el método Book::create(), vamos avisando que Laravel nos arrojará una excepción cuando se intente crear el nuevo libro.

No es la primera vez que nos aparece un error similar, así que vamos a intentar concretar ya de una manera sencilla qué es lo que está pasando.

El método Book::create() nos permite crear un elemento e insertarlo en la base de datos. Para ello recibe un array y usa todos los datos que le estamos pasando. Esos datos en nuestro ejemplo vienen directamente de la solicitud y los volcamos tal cual para poder crear ese nuevo libro:

Imagina que viene a través de la solicitud un dato que realmente no estábamos esperando, por ejemplo un dato de control que usas internamente para saber el estado de un libro y no deseas que sea parte de la entrada del usuario. ¿Cómo podría ocurrir que te manden otros datos, además de los que deseas? pues simplemente un usuario con conocimientos mínimos podría crear otros campos en el formulario, editando la página con las herramientas de desarrolladores y así se enviarían también en la solicitud por el método POST al enviar ese formulario normalmente.

Así que Laravel, para evitar estas cosas, al usar el método create() que es potencialmente peligroso por una posible inyección de datos no deseados, obliga a que tengas declarados en el modelo aquellos campos que se van a poder insertar al hacer un create().

Nota: Hay otros métodos de Eloquent para crear elementos en las tablas, que no tendrían este problema porque de manera explícita se indican campo a campo las columnas a insertar con los valores.

Esta configuración se realiza a través de una propiedad que tendremos que crear dentro del modelo, llamada $fillable. El código te quedará así:

Vistas de la aplicación

Ya solo nos queda ver las vistas que hemos creado para esta práctica. Todas las hemos situado en la carpeta resources/views/libro.

Nota: Todavía nos quedan cosas por ver de las vistas, sobre todo del motor de plantillas Blade, pero recuerda que ya pudimos encontrar una introducción a las vistas.

Vista libro.todos: (archivo todos.php)
Esta vista hace el recorrido a array de libros que se le ha pasado y los va mostrando uno a uno.

En este caso usamos un “foreach” clásico de PHP (con el código sugerido como alternativa a las vistas), aunque más tarde al aprender Blade veremos una forma más clara de escribir este mismo código.

Vista libro.mostrar: (archivo mostrar.php) Esta segunda vista muestra el detalle de un libro.

Nota: Es cierto que había otros campos en la tabla de libro, pero no los hemos querido usar por ahora, para no incrementar la dificultad de esta práctica.

vista libro.formlibro: archivo formlibro.blade.php Esta tercera vista, y última, es la que usaremos para mostrar el formulario de un libro, que de momento estamos usando para la creación de libros. Hemos elegido como extensión .blade.php porque vamos a usar un pedazo de código con sintaxis blade para mostrar los posibles errores de validación de los datos del formulario.

Esta vista tiene varios detalles importantes, primero el recorrido a los errores de validación y luego la “memoria” en los campos de formulario para que sean capaces de recordar su estado cuando fue enviado el formulario la última vez. Todo esto no lo vamos a explicar porque se vio con suficiente detalle en el capítulo de validaciones en Laravel.

Con esto termina esta práctica, ya solo faltaría poner en marcha el ejercicio accediendo a las rutas de la aplicación definidas.

Autor

Miguel Angel Alvarez

Seguir a midesweb

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Subir

Comentarios

04/1/2016

Felicitación

Excelente aporte, breve, consiso y claro.

29/7/2016

Error en comillas

Cuando creais las rutas, en la línea
usáis una comilla "tipográfica" en lugar de una comilla recta y al copiarpegar el código peta :-)

05/10/2016

necesito

quiero saber como esta implementado el mecanismo de acceso a datos

in4es

Lets for arguments sake say this is our database columns : username, password and finally accessLevel

With the create method you pass through an Array of post data lets take this example :

now with this approach we are not assigning input to specific fields in the database like we would using the save() approach so i can easily modify the html add a form element with the id accessLevel ( with a lucky guess or something ) and set it equal to 1 and that for instance that could resemble admin access.

With the save() method we assign exactly what we want to store where thus there cannot be a mass assignment even if post data is added to the request it will just be discarded.

If however you are not passing Input::all() to the create() method and simply passing input::only() i think it might be something with the design regarding the create method. I'm not to sure about this, but whether you pass input::all() or input::only(), the create() method still gets and array so i think it won't be able to differentiate between the 2 thus the mass assignment exception is added and $fillable or $gauderd array is needed within the model to discard unwanted post data.

This is just my thought and how i understand the subject. take it with a pinch of salt.

edit...

Just wanting to add i treat Laravel like a TV remote, i press the button and the channel changes, i'm not too concerned how the remote does what it does all i know is i get the channel i want. :) if you really want to know why i would suggest having a look at the create() method and see if you can gather why this is the case.

One thought on “Massassignmentexception In Model.Php Laravel 5 Book

Leave a Reply

Your email address will not be published. Required fields are marked *